package com.pnnd.utils;

import java.util.*;

public class IntList {

    private int size;
    private int[] data;

    public IntList(int capacity){
        this.data = new int[capacity];
        this.size = 0;
    }

    public IntList(){
        this(16);
    }
    
    public int size() {
        return this.size;
    }

    
    public boolean isEmpty() {
        return this.size == 0;
    }

    
    public boolean contains(int o) {
        return Arrays.binarySearch(this.data,o) > -1;
    }
    
    public int[] toArray() {
        return Arrays.copyOf(this.data,this.size);
    }

    
    public boolean add(int o) {

        this.checkCapacity(1);

        this.data[this.size] = o;

        this.size++;

        return true;
    }

    
    public boolean removeElement(int o) {

        int index = this.indexOf(o);

        if(index == -1){
            return false;
        }

        this.remove(index);

        return true;
    }

    
    public boolean addAll(int[] c) {

        if(c == null){
            throw new NullPointerException();
        }

        this.checkCapacity(c.length);

        System.arraycopy(c,0,this.data,this.size,c.length);

        this.size += c.length;

        return true;
    }

    
    public boolean addAll(int index, int[] c) {

        if(index > this.size){
            throw new IndexOutOfBoundsException();
        }

        int[] tmp = Arrays.copyOfRange(this.data,index,this.size);

        this.size = index;

        return this.addAll(c) && this.addAll(tmp);
    }

    
    public void clear() {
        this.size = 0;
    }

    
    public boolean equals(Object o) {

        if(o instanceof IntList){
            return Arrays.equals(this.data,((IntList) o).data);
        }

        return false;
    }

    
    public int hashCode() {
        return Arrays.hashCode(this.data);
    }

    
    public int get(int index) {

        if(index > this.size){
            throw new IndexOutOfBoundsException();
        }

        return this.data[index];
    }

    
    public Object set(int index, int element) {

        if(index > this.size){
            throw new IndexOutOfBoundsException();
        }

        return this.data[index] = element;
    }

    
    public void add(int index, int element) {
        this.addAll(index,new int[]{element});
    }

    
    public int remove(int index) {

        if(index > this.size){
            throw new IndexOutOfBoundsException();
        }

        int result = this.data[index];

        int[] tmp = Arrays.copyOfRange(this.data,index,this.size);

        this.size = index - 1;

        this.addAll(tmp);

        return result;
    }

    
    public int indexOf(int o) {
        return Arrays.binarySearch(this.data,o);
    }

    
    public int lastIndexOf(int o) {

        int result = Arrays.binarySearch(this.data,o);

        while(result != -1){
            int temp = Arrays.binarySearch(this.data,result,this.data.length-1,o);

            if(temp == -1){
                break;
            }

            result = temp;
        }

        return result;
    }

    
    public int[] subList(int fromIndex, int toIndex) {

        if(fromIndex > this.size){
            throw new IndexOutOfBoundsException();
        }

        return Arrays.copyOfRange(this.data,fromIndex,Math.min(toIndex,this.size));
    }

    
    public boolean retainAll(int[] c) {

        if(c==null){
            throw new NullPointerException();
        }

        boolean result = true;

        for(int i=0;i<this.size;i++){

            if(Arrays.binarySearch(c,this.data[i])>-1){
                result = result && this.removeElement(this.data[i]);
            }
        }

        return result;
    }

    
    public boolean removeAll(int[] c) {
        if(c==null){
            throw new NullPointerException();
        }

        boolean result = true;

        for(int i=0;i<c.length;i++){
            result = result && this.removeElement(c[i]);
        }

        return result;
    }

    
    public boolean containsAll(int[] c) {
        if(c==null){
            throw new NullPointerException();
        }

        boolean result = true;

        for(int i=0;i<c.length;i++){
            result = result && this.contains(c[i]);
        }

        return result;
    }

    private void checkCapacity(int requiredSize){
        if(this.size + requiredSize == this.data.length){
            int[] tmp = this.data;

            this.data = new int[tmp.length*3];

            System.arraycopy(tmp,0,this.data,0,tmp.length);
        }
    }
}
